home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Media 20
/
PC MEDIA CD20.iso
/
share
/
prog
/
cursoasm
/
cap3.msg
< prev
next >
Wrap
Text File
|
1993-06-17
|
10KB
|
222 lines
INTRODUCCION AL ASM: LA INSTRUCCION MOV (I)
===========================================
La operación más básica que el uP es capaz de realizar es el movimiento de
datos (números) de un lugar a otro. Puede moverlos de un registro a otro, de
un registro a la memoria o de la memoria a un registro.
La instrucción en lenguaje ensamblador que representa esta operación se
denomina 'MOV', del inglés 'move', y puede traducirse en muchos códigos de
operación distintos en función del origen y el destino del dato. La instrucción
MOV tiene dos operandos, que van después del 'mov' dejando uno o varios separa-
dores entre el 'MOV' y el primer operando (diciendo separadores nos referire-
mos siempre a los espacios - carácter 32d o 20h - y a los tabuladores - carác-
ter 09) y separados por una coma y/o varios separadores. La sintáxis es la
siguiente:
MOV destino,origen
En esta instrucción 'origen' significa el lugar de donde el uP recoge el
dato a mover y 'destino' el lugar donde lo escribe después. Estos operandos
pueden ser de muchas formas, y en función de la forma de estos se habla del
'modo de direccionamiento', que es el modo en como se accede al destino o al
origen. Podríamos dar una larga y tediosa lista de los nombres de todos los
modos de direccionamiento, pero lo que haremos será ir viendo ejemplos fácil-
mente asimilables, de forma que luego quien quiera pueda aprenderse los nombres
de los distintos modos de direccionamiento.
Uno de los usos más sencillos es el de mover un dato de un registro a otro.
Por ejemplo, para mover el dato del registro BX al registro AX escribiríamos:
MOV AX,BX
El contenido anterior del registro AX se pierde, de manera que el valor del
BX 'pisa' lo que hubiera en el AX. Después de ejecutarse esta instrucción, los
registros BX y AX contendrán el mismo valor, el contenido anterior del BX.
De la misma forma, podemos comprender las siguientes instrucciones:
MOV AX,DS
MOV ES,AX
MOV DX,AX
...
Hacemos aquí un pequeño inciso para explicar cómo se añaden los comentarios
a los listados en ASM: cuando el ensamblador encuentra un punto y coma (carác-
ter ';'), ignora todos los caracteres hasta que encuentra el final de la línea
actual. Por tanto, las instrucciones anteriores se pueden comentar:
MOV AX,DS ; Carga AX con el valor del DS
MOV ES,AX ; ES = AX
MOV DX,BX ; DX <- BX
Esta convención para los comentarios la aceptan los ensambladores como el
MASM o el TASM, pero también lo acepta el DEBUG del MS-DOS (más adelante
veremos cómo usarlo).
Retomemos los usos de la instrucción MOV. Otra de las posibilidades es
cargar en un registro directamente un valor. Por ejemplo, podemos inicializar
los registros AX, BX, CX y DX a 1,2,3 y 4 respectivamente con las siguientes
instrucciones:
MOV AX,1
MOV BX,2
MOV CX,3
MOV DX,4
Un punto que me gustaría destacar respecto al uso 'MOV reg,valor' es que
los registros de segmento no se pueden cargar directamente. Es decir, no
existe código de operación para la instrucción
MOV DS,0040h
Sino que hay que hacerlo necesariamente por medio de otro registro:
MOV AX,0040h
MOV DS,AX
Otro aspecto que querría comentar respecto a la instrucción 'MOV': el
código de operación de las instrucciones de transferencia entre registros in-
corpora algunos campos que especifican de qué registro a qué registro se mueve
el dato. Pero en estas últimas instrucciones, el dato que se quiere cargar en
el registro va con el propio código de operación. Es decir, el 8086 espera
encontrar el valor a guardar inmediatamente después de lo que constituye el
verdadero 'opcode' (o código de operación), que es el que identifica a la ins-
trucción y no depende del valor a guardar. Por eso, las primeras instrucciones
(MOV AX,BX; etc...) sólo ocupan dos bytes (ambos forman el código de operación
de la instrucción), mientras que las otras (MOV AX,1; etc...) ocupan dos o tres
bytes. ¿A qué se debe esta diferencia del tamaño? Se debe a una característica
del 8086 de la que todavía no hemos hablado:
Cuando se diseñó el 8086, se penso (hicieron bien) que en algunos casos
interesaría acceder por separado al byte alto y byte bajo que componen los
registros, de manera que podamos operar con valores del tamaño de un byte. Por
tanto, se incluyeron instrucciones que en lugar de operar sobre los registros
de 16 bits completos operaban sobre los bytes que los componen. Esta subdivi-
sión sólo se hizo para los cuatro registros de propósito general, y en ASM se
identifican con los siguientes nombres:
AX -> AH (byte alto) y AL (byte bajo)
BX -> BH ( " " ) y BL ( " " )
CX -> CH ( " " ) y CL ( " " )
DX -> DH ( " " ) y DL ( " " )
Así, las siguientes instrucciones también tienen su correspondiente
código de operación. Espero que su función resulte obvia:
MOV AL,BL
MOV CH,CL
MOV DL,5
MOV BH,2
Es necesario dejar claro que los registros AL y AH, por ejemplo, son parte
del propio AX y por tanto no son independientes de éste. Por tanto, tras
ejecutar las siguientes instrucciones:
MOV AX,0FFFFh
MOV AL,00
MOV AH,00
El registro AX valdrá 0000, ya que tanto su byte alto como su byte bajo se
han puesto a cero.
El tamaño de la instrucción 'MOV reg,valor', volviendo a donde lo dejamos,
depende del tamaño del registro que se modifique. Si se modifica un registro de
16 bits, el dato que viene a continuación debe ser de éste tamaño, por lo que
además del byte con el opcode necesitamos otros dos con el valor, por lo que el
total es de tres bytes. En cambio, en una instrucción como 'MOV AL,00' sólo es
necesario un byte con el valor después del opcode, por lo que el tamaño total
de la instrucción es de dos bytes.
Otro de los posibles usos de la instrucción MOV es el de cargar un registro
con el contenido de una posición de memoria. El operando destino indicará el
registro en el que se debe almacenar el valo, mientras que el operando origen
será la dirección de la que se debe cargar el dato. Para indicar que lo que se
quiere cargar es el valor contenido en la posición de memoria dada, se encierra
la dirección entre corchetes:
MOV AL,[0000] ; Carga el valor de la posición cero en AL,
; a diferencia de la siguiente instrucción,
MOV AH,00 ; que carga el VALOR 0 en AH
Ya que con los 16 bits que damos como dirección de memoria (no se pueden
dar los 20 bits completos) no se puede generar la dirección completa, se usa
el registro DS para formarla como vimos en el capítulo anterior. Más adelante
veremos cómo se puede especificar que se use otro registro.
Esto se denomina 'direccionamiento indirecto', en el que el operando es una
posición de memoria de la que cargar el dato en lugar del valor a cargar. A
proposito, el dar directamente el valor se denomina 'direccionamiento
inmediato'.
Si el registro indicado es de 16 bits, se carga el byte bajo de la dirección
dada y el byte alto de la siguiente (ordenamiento Intel, ¿recordáis?).
MOV AX,[0000] ; Carga el valor de la posición 0 en AL
; y el de la posición 1 en AH
Al igual que se puede cargar un registro con el contenido de una posición
de memoria, se puede almacenar el contenido de un registro en una posición de
memoria. La instrucción, como habréis adivinado, queda así:
MOV [0000],AX ; Almacena AL en la pos. 0 y AH en la pos. 1
MOV [0505h],AL ; Almacena AL en la pos 0505h
Aunque así podemos acceder a posiciones de memoria determinadas, a menudo
interesa acceder a la posición de memoria indicada por un registro. En el caso
del 8086, es posible acceder a la posición de memoria apuntada por BX, tanto
para lectura como para escritura, de esta forma:
MOV AL,[BX] ; Carga en AL el valor almacenado en la
; posición de memoria dada por BX
MOV [BX],DX ; Almacena DL en la posición dada por BX,
; y DH en la posición siguiente
Para darnos más posibilidades, los códigos de operación del 8086 incluyen
un acceso a memoria a una posición nn bytes más adelante de la dada por BX,
todo en una sola instrucción:
MOV AX,[BX+15d] ; Carga los dos bytes de la posición apuntada
; por BX más 15 y de la siguiente
MOV [BX-12d],DL ; Almacena DL en la dirección dada por BX
; menos 12
Este valor que se suma a BX antes de generar el acceso a memoria viene, de
la misma manera que el valor en el direccionamiento inmediato, inmediatamente
después del código de operación, y forma parte de la instrucción. Si el valor
del desplazamiento está entre -128d y +127d, es decir, 'cabe' en un byte
(ya que el desplazamiento se interpreta como entero con signo), se genera una
instrucción un byte más corta que si el valor necesita una palabra entera. De
todas formas, el desplazamiento (el valor que se suma a BX) nunca puede salirse
de una palabra.
Hemos visto que el acceso a memoria por medio de un registro lo hacemos
siempre con el BX. De hecho, no existen códigos de operación para acceder con
el AX, el CX y el DX. Por tanto las siguientes instrucciones no las acceptará
el ensamblador:
MOV BX,[AX] ; MAL
MOV CL,[DX] ; MAL
Y ahora, viendo esta limitación de registros para apuntar a memoria, llega
el momento de introducir otros dos registros: el SI ('Source Index') y el DI
('Destination Index'). Estos registros admiten todos los modos de direcciona-
miento que hemos visto, y además algunos que todavía no conocemos. La única
diferencia es que no se puede acceder por separado a los bytes alto y bajo, por
lo que siempre usaremos los registros 'enteros'.
Por ejemplo, podemos hacer cosas como:
MOV AX,0040h
MOV DS,AX ; Segmento de datos a partir de 00400h absoluta
MOV SI,2
MOV AX,[SI] ; Carga el byte almacenado en 00402h absoluta
; en AL, y el de 00403h en AH
Bueno, en el siguiente capítulo seguiremos con más usos de la instrucción
MOV (más modos de direccionamiento) y veremos cómo experimentar con el DEBUG.
Pensaba explicar todo esto en un sólo capítulo, pero se me alarga demasié.
Salut!!! :-)
Jon